/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package monopoly.gamemanager;

import Monopol.Monopol;
import Monopol.MonopolExceptions.MonopolErrors;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author blecherl
 */
public class MonopolyGameManager {

    Map<String, GameDetails> games;//games table
    Monopol Actual_game;//the real played game
    private static MonopolyGameManager instance;

    static {
	instance = new MonopolyGameManager();
    }

    public MonopolyGameManager() {
	games = new HashMap<String, GameDetails>();
    }

    public static MonopolyGameManager getInstance() {
	return instance;
    }

    public boolean addGame(String gameName, int humanPlayers, int computerizedPlayers, boolean useAutomaticDiceRoll) {
	try {
	    if (isGameExists(gameName)) {
		return false;
	    } else if (games.size() > 1) {
		return false;// we don't support more then one game at this moment
	    } else {
		games.put(gameName, new GameDetails(gameName, humanPlayers, computerizedPlayers, useAutomaticDiceRoll));
		return true;
	    }
	} catch (Exception e) {
	    return false;
	}
    }

    private boolean isGameExists(String gameName) {
	Boolean hasKey;
	try {
	    hasKey = games.containsKey(gameName);
	} catch (Exception e) {
	    hasKey = false;
	}
	return hasKey;
    }

    public boolean isGameStarted(String gameName) {
	return isGameExists(gameName) && games.get(gameName).isGameStarted();
    }

    public boolean isGameActive(String gameName) {
	return isGameExists(gameName) && games.get(gameName).isGameActive();
    }

    /**
     * Joins the Player to the Game
     * @param gameName The Game Name
     * @param playerName The Player Name to Join
     * @param ID The Player Id
     * @return The Players Array Size
     */
    public int joinPlayer(final String gameName, String playerName, Integer ID) {
	// Check if the Game Exists
	if (isGameExists(gameName)) {
	    // Get the players Array Size
	    int joinPlayer = games.get(gameName).joinPlayer(playerName, ID);
	    //checks if max human players join the game
	    if (games.get(gameName).getJoinedHumanPlayers() == games.get(gameName).humanPlayers) {
		//get the monopol instance
		Actual_game = Monopol.getInstance();
		//created a new thread and starts the game
		Thread thread = new Thread(new Runnable() {

		    public void run() {
			GameDetails get = games.get(gameName);

			Actual_game.start((games.get(gameName)).getPlayer(), isAutomaticDiceRoll(gameName), gameName);
		    }
		});
		thread.start();

	    }
	    //add new player to game and Return the ID
	    return joinPlayer - 1;
	} else {
	    return -1;
	}
    }

    public ArrayList<String> getGamesNames() {
	ArrayList<String> res = new ArrayList<String>();
	for (String game : games.keySet()) {
	    res.add(game);
	}
	return res;
    }

    public int getComputerizedPlayers(String gameName) {
	return isGameExists(gameName) ? games.get(gameName).computerizedPlayers : -1;
    }

    public int getHumanPlayers(String gameName) {
	return isGameExists(gameName) ? games.get(gameName).humanPlayers : -1;
    }

    public int getJoinedHumanPlayers(String gameName) {
	return isGameExists(gameName) ? games.get(gameName).getJoinedHumanPlayers() : -1;
    }

    public boolean isAutomaticDiceRoll(String gameName) {
	return isGameExists(gameName) ? games.get(gameName).useAutomaticDiceRoll : true;
    }

    public String[] getPlayersNames(String gameName) {
	if (!isGameExists(gameName)) {
	    return new String[0];
	}

	List<String> names = new LinkedList<String>();
	for (PlayerDetails details : games.get(gameName).players) {
	    names.add(details.name);
	}
	return names.toArray(new String[names.size()]);
    }

    public boolean[] getPlayersHumanity(String gameName) {
	if (!isGameExists(gameName)) {
	    return new boolean[0];
	}
	boolean[] results = new boolean[games.get(gameName).players.size()];
	for (int index = 0; index < games.get(gameName).players.size(); index++) {
	    results[index] = games.get(gameName).players.get(index).isHuman;
	}
	return results;
    }

    public boolean[] getPlayersActive(String gameName) {
	if (!isGameExists(gameName)) {
	    return new boolean[0];
	}
	boolean[] results = new boolean[games.get(gameName).players.size()];
	for (int index = 0; index < games.get(gameName).players.size(); index++) {
	    results[index] = games.get(gameName).players.get(index).isActive;
	}
	return results;
    }

    public String IDtoName(Integer ID) {
//find player and return his name
	return Monopol.getInstance().getplayer(ID, 0).getName();
    }

    public int[] getPlayersAmounts(String gameName) {
	if (!isGameExists(gameName)) {
	    return new int[0];
	}
	int[] results = new int[games.get(gameName).players.size()];
	for (int index = 0; index < games.get(gameName).players.size(); index++) {
	    results[index] = games.get(gameName).players.get(index).amount;
	}
	return results;
    }

    public void resign(Integer ID) {
	try {
	    Actual_game.resignPlayer(ID);
	} catch (MonopolErrors ex) {
	    Logger.getLogger(MonopolyGameManager.class.getName()).log(Level.SEVERE, null, ex);
	}
    }

    class GameDetails {

	private String gameName;
	private int humanPlayers;
	private int computerizedPlayers;
	private boolean useAutomaticDiceRoll;
	private List<PlayerDetails> players;

	public GameDetails(String gameName, int humanPlayers, int computerizedPlayers, boolean useAutomaticDiceRoll) {
	    this.gameName = gameName;
	    this.humanPlayers = humanPlayers;
	    this.computerizedPlayers = computerizedPlayers;
	    this.useAutomaticDiceRoll = useAutomaticDiceRoll;
	    this.players = new LinkedList<PlayerDetails>();
	    //added computer player details
	    for (Integer i = 0; i < computerizedPlayers; i++) {
		//create the detail fron non human players
		Integer index = i + 1;//creating the index foor the player
		players.add(new PlayerDetails("Dummy" + index.toString(), -i - 1, false));
	    }
	}

	public boolean isGameStarted() {
	    return this.gameName != null;
	}

	public boolean isGameActive() {
	    return isGameStarted() && (this.humanPlayers + this.computerizedPlayers == this.players.size());
	}

	public int joinPlayer(String playerName, Integer ID) {
	    this.players.add(new PlayerDetails(playerName, ID, true));
	    return this.players.size();
	}

	public int getJoinedHumanPlayers() {
	    return this.players.size() - this.computerizedPlayers;
	}

	public String[] getPlayersNames() {
	    List<String> names = new LinkedList<String>();
	    for (PlayerDetails details : players) {
		names.add(details.name);
	    }
	    return names.toArray(new String[names.size()]);
	}

	public boolean[] getPlayersHumanity() {
	    boolean[] results = new boolean[players.size()];
	    for (int index = 0; index < players.size(); index++) {
		results[index] = players.get(index).isHuman;
	    }
	    return results;
	}

	public boolean[] getPlayersActive() {
	    boolean[] results = new boolean[players.size()];
	    for (int index = 0; index < players.size(); index++) {
		results[index] = players.get(index).isActive;
	    }
	    return results;
	}

	public double[] getPlayersAmounts() {
	    double[] results = new double[players.size()];
	    for (int index = 0; index < players.size(); index++) {
		results[index] = players.get(index).amount;
	    }
	    return results;
	}

	public List<PlayerDetails> getPlayer() {
	    return players;
	}

	/**
	 * Translates a Player ID to its Name
	 * @param ID The Player ID to Translate
	 * @return The Player NAme
	 */
	public String IDtoName(Integer ID)//gets an id and convert it to name
	{
	    try {
		Boolean SuchID = false;
		// Get the Number of Players
		Integer numOfPlayers = players.size();
		// Set a Temp User for Testing
		PlayerDetails tmpPlayer = null;
		// Initialize the Counter
		int i = 0;
		// Loop Until a Player is Found or Until Finished going thru all the Players
		while (i < numOfPlayers && SuchID != true) {
		    // Get the Player at Place I
		    tmpPlayer = players.get(i);
		    // Check the Player ID
		    if (tmpPlayer.getID() == ID) {
			// We Found the Requested Player
			SuchID = true;
		    } else {
			// Increment the Counter
			i++;
		    }
		}
		// Verify that we Found a Player
		if (SuchID) {
		    // Return the Player Name
		    return tmpPlayer.getName();
		} else {
		    // No Player was Found - Return Null
		    return null;
		}
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	    // An Error has Occourd - Return Null
	    return null;
	}
    }

    public class PlayerDetails {

	private String name;
	private boolean isHuman;
	private boolean isActive;
	private int amount;
	private Integer ID = null;//if player is human the ID will contain a uniqe number ,else null

	public PlayerDetails(String name, boolean isHuman) {
	    this.name = name;
	    this.isHuman = isHuman;
	    this.isActive = true;
	    this.amount = 1500;
	}

	public PlayerDetails(String name, Integer ID, boolean isHuman) {
	    this.name = name;
	    this.isHuman = isHuman;
	    this.isActive = true;
	    this.amount = 1500;
	    this.ID = ID;
	}

	public boolean PlayerIsHuman() {
	    return isHuman;
	}

	public String getName() {
	    return name;
	}

	public int getAmount() {
	    return amount;
	}

	public Integer getID() {
	    return ID;
	}
    }

    /**
     * Removes the Game from the Games Array
     * @param GameName The Game Name to Remove
     */
    public void removeGame(String GameName) {
	games.remove(GameName);
    }
}
